/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_Studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#pragma once


#include <基本类型.h>
#include <向量.h>




enum E_FlexRelaxationMode
{
	e_FlexRelaxationGlobal = 0,	//!< The relaxation factor is a fixed multiplier on each constraint's position delta
	e_FlexRelaxationLocal = 1		//!< The relaxation factor is a fixed multiplier on each constraint's delta divided by the particle's constraint count, convergence will be slower but more reliable
};


typedef struct {
	// cloth params
	vec3	wind;						//!< Constant acceleration applied to particles that belong to dynamic triangles, drag needs to be > 0 for wind to affect triangles
	float32 drag;							//!< Drag force applied to particles belonging to dynamic triangles, proportional to velocity^2*area in the negative velocity direction
	float32 lift;							//!< Lift force applied to particles belonging to dynamic triangles, proportional to velocity^2*area in the direction perpendicular to velocity and (if possible), parallel to the plane normal


	vec3	gravity;					//!< Constant acceleration applied to all particles
	float32 radius;						//!< The maximum interaction radius for particles
	float32 solidRestDistance;			//!< The distance non-fluid particles attempt to maintain from each other, must be in the range (0, radius]
	float32 fluidRestDistance;			//!< The distance fluid particles are spaced at the rest density, must be in the range (0, radius], for fluids this should generally be 50-70% of mRadius, for rigids this can simply be the same as the particle radius



	int32 numIterations;					//!< Number of solver iterations to perform per-substep

		 
	// common params
	float32 dynamicFriction;				//!< Coefficient of friction used when colliding against shapes
	float32 staticFriction;				//!< Coefficient of static friction used when colliding against shapes
	float32 particleFriction;				//!< Coefficient of friction used when colliding particles
	float32 restitution;					//!< Coefficient of restitution used when colliding against shapes, particle collisions are always inelastic
	float32 adhesion;						//!< Controls how strongly particles stick to surfaces they hit, default 0.0, range [0.0, +inf]
	float32 sleepThreshold;				//!< Particles with a velocity magnitude < this threshold will be considered fixed
	float32 maxSpeed;						//!< The magnitude of particle velocity will be clamped to this value at the end of each step
	float32 maxAcceleration;				//!< The magnitude of particle acceleration will be clamped to this value at the end of each step (limits max velocity change per-second), useful to avoid popping due to large interpenetrations 
	float32 shockPropagation;				//!< Artificially decrease the mass of particles based on height from a fixed reference point, this makes stacks and piles converge faster
	float32 dissipation;					//!< Damps particle velocity based on how many particle contacts it has
	float32 damping;						//!< Viscous drag force, applies a force proportional, and opposite to the particle velocity

	
	// fluid params
	float32 cohesion;						//!< Control how strongly particles hold each other together, default: 0.025, range [0.0, +inf]
	float32 surfaceTension;				//!< Controls how strongly particles attempt to minimize surface area, default: 0.0, range: [0.0, +inf]    
	float32 viscosity;					//!< Smoothes particle velocities using XSPH viscosity
	float32 vorticityConfinement;			//!< Increases vorticity by applying rotational forces to particles
	float32 anisotropyScale;				//!< Control how much anisotropy is present in resulting ellipsoids for rendering, if zero then anisotropy will not be calculated, see NvFlexGetAnisotropy()
	float32 anisotropyMin;				//!< Clamp the anisotropy scale to this fraction of the radius
	float32 anisotropyMax;				//!< Clamp the anisotropy scale to this fraction of the radius
	float32 smoothing;					//!< Control the strength of Laplacian smoothing in particles for rendering, if zero then smoothed positions will not be calculated, see NvFlexGetSmoothParticles()
	float32 solidPressure;				//!< Add pressure from solid surfaces to particles
	float32 freeSurfaceDrag;				//!< Drag force applied to boundary fluid particles
	float32 buoyancy;						//!< Gravity is scaled by this value for fluid particles

	// diffuse params
	float32 diffuseThreshold;				//!< Particles with kinetic energy + divergence above this threshold will spawn new diffuse particles
	float32 diffuseBuoyancy;				//!< Scales force opposing gravity that diffuse particles receive
	float32 diffuseDrag;					//!< Scales force diffuse particles receive in direction of neighbor fluid particles
	int32 diffuseBallistic;				//!< The number of neighbors below which a diffuse particle is considered ballistic
	float32 diffuseLifetime;				//!< Time in seconds that a diffuse particle will live for after being spawned, particles will be spawned with a random lifetime in the range [0, diffuseLifetime]

	// collision params
	float32 collisionDistance;			//!< Distance particles maintain against shapes, note that for robust collision against triangle meshes this distance should be greater than zero
	float32 particleCollisionMargin;		//!< Increases the radius used during neighbor finding, this is useful if particles are expected to move significantly during a single step to ensure contacts aren't missed on subsequent iterations
	float32 shapeCollisionMargin;			//!< Increases the radius used during contact finding against kinematic shapes

	//float32 planes[8][4];					//!< Collision planes in the form ax + by + cz + d = 0
	vec3 planes[2];					//!< Collision planes in the form ax + by + cz + d = 0
	int numPlanes;						//!< Num collision planes

	E_FlexRelaxationMode relaxationMode;//!< How the relaxation is applied inside the solver
	float32 relaxationFactor;				//!< Control the convergence rate of the parallel solver, default: 1, values greater than 1 may lead to instability
	
	float32 m_时间步进;
	uint32	m_飞溅粒子数量;
	uint32	m_粒子数量;

}S_FlexParams;



uint64	f_NvFlex_初始化参数(uint32 设备);
void	f_NvFlex_释放(uint64 key);

void	f_NvFleX_重置begin(uint64 key, uint32 飞溅粒子数量, bool 重置大小 = true);
void	f_NvFleX_重置end(uint64 key, bool 重置大小 = true);

//void	f_NvFleX_设置粒子半径();
float32	f_NvFleX_更新(uint64 key, S_FlexParams& Params);

uvec2	f_NvFleX_添加流体(uint64 key, vec3* point, float32* 质量, float32 速度, uint32 num, bool 是否激活, float32 抖动 = 0.001f);
uvec2	f_NvFleX_添加刚体(uint64 key, vec3* point, float32* 质量, vec4* 法线, float32 速度, uint32 num, uint32 ID, float32 刚性, float32 抖动 = 0.001f);
uvec2	f_NvFleX_发射(uint64 key, uvec2 区间, vec3* point, vec3* dir, bool 是否激活, float32 抖动 = 0.001f);
//uvec2	f_NvFleX_重置()

void	f_NvFleX_set流体(uint64 key, vec3* point, float32* 质量, float32 速度, uvec2 区间, bool 是否激活, float32 抖动 = 0.001f);
void	f_NvFleX_set刚体(uint64 key, vec3* point, float32* 质量, vec4* 法线, float32 速度, uvec2 区间, uint32 ID, float32 刚性, float32 抖动 = 0.001f);



void	f_NvFleX_取更新数据(uint64 key, std::vector<vec4>& point);
void	f_NvFleX_取飞溅数据(uint64 key, std::vector<vec4>& point, std::vector<vec4>& dir);
void	f_NvFleX_取变换数据(uint64 key, std::vector<vec4>& rot, std::vector<vec3>& loc);

void	f_NvFleX_取区间坐标数据(uint64 key, uvec2 r, std::vector<vec3>& point);
//void	f_NvFleX_取区间速度数据(uint64 key, uvec2 r, std::vector<vec3>& point);
//void	f_NvFleX_取区间激活数据(uint64 key, uvec2 r, std::vector<vec3>& point);
//void	f_NvFleX_取区间类型数据(uint64 key, uvec2 r, std::vector<vec3>& point);
void	f_NvFleX_get数据(uint64 key, std::vector<vec4>& point, std::vector<vec4>& 飞溅, std::vector<vec3>& 速度, std::vector<int32>& 激活);




